package admin

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"go-cmdb/controllers"
	"go-cmdb/models"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type ApiRes struct {
	Data interface{} `json:"data"`
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
}

//AdminController 重写基类
type AdminController struct {
	controllers.BaseController
}

func (b *AdminController) IgnoreLayout(fn func(act string) bool) {
	_, act := b.Controller.GetControllerAndAction()
	if fn(act) {
		b.Layout = ""
	}
}
func (b *AdminController) CurUser() (u *models.User, err error) {

	var auth *AdminAuthInfo
	auth, err = b.GetAuthUser()
	if err != nil {
		return
	}
	u, err = models.NewUser().Find(auth.UserID)
	if err != nil {
		return
	}
	return

}

type AdminAuthInfo struct {
	UserID uint64 `json:"user_id"`
}

func (b *AdminController) GetAuthUser() (auth *AdminAuthInfo, err error) {
	if val := b.Ctx.Input.Session(SESSION_KEY); val != nil {
		if err = json.Unmarshal([]byte(val.(string)), &auth); err != nil {
			return
		}
		return
	}
	return nil, errors.New("not found")

}
func (b *AdminController) SetAuthUser(auth *AdminAuthInfo) (err error) {

	by, err := json.Marshal(auth)
	if err == nil {
		b.Ctx.Output.Session(SESSION_KEY, string(by))
		return nil
	}
	return err

}

func (b *AdminController) DelAuthUser() error {
	return b.Ctx.Input.CruSession.Delete(context.Background(), SESSION_KEY)
}

func (b *AdminController) AllowAnonymous(fn func(act string) bool) {
	_, act := b.Controller.GetControllerAndAction()
	if fn(act) {
		b.setNoAuth()
	}
}

func (b *AdminController) setNoAuth() {
	b.Ctx.Input.SetData("no_auth", true)
}
func (b *AdminController) getNoAuth() interface{} {
	return b.Ctx.Input.GetData("no_auth")
}

//Prepare action前置处理
func (b *AdminController) Prepare() {

	defer func() {

		if err := recover(); err != nil {
			if !b.IsAjax() {
				b.ErrorView(controllers.ErrorMsg{
					Code: 500,
					Msg:  b.ErrorFormat(err),
				})
				return
			}

			b.RES(500, nil, b.ErrorFormat(err))
			return

		}
	}()

	b.TplExt = "html"
	b.Data["ts"] = time.Now().UnixNano()
	b.TplPrefix = "admin/"
	//设置模板
	b.Layout = "admin/layout.html"

	//redirect_url
	redirectUrl := b.RedirectUrl()
	b.Data["redirect_url"] = redirectUrl

	if ok := b.Authorization(); !ok {
		return
	}

	if !b.IsAjax() {

		auth, _ := b.GetAuthUser()
		if auth != nil {
			curUser, _ := models.NewUser().Find(auth.UserID)
			if curUser == nil || curUser.Status != 1 {
				_ = b.DelAuthUser()
				msg := ""
				code := 0
				if curUser.Status == 2 {
					msg = "该账号已被停用"
					code = 403
				} else if curUser.Status == 0 {
					msg = "该账号不存在"
					code = 404
				}
				b.ErrorView(controllers.ErrorMsg{
					Code: code,
					Msg:  msg,
				})
				return
			}

			b.Data["us"] = curUser
			//查询菜单
			mList, _ := models.NewMenu().GetMenuTree(curUser.GetRoleIds())
			if len(mList) <= 0 {
				b.ErrorView(controllers.ErrorMsg{
					Code: 403,
					Msg:  "没有权限",
				})
				return
			}

			////验证权限
			//reqUrl := b.Ctx.Request.URL.Path
			//if linq.From()

			b.Data["menu"] = mList
		} else {
			b.Data["us"] = models.NewUser()

		}
		tag := b.Ctx.Request.URL.Query().Get("tag")
		b.Data["tag"] = tag
		//配置
		setMap := models.NewSetting().GetMap()
		b.Data["sets"] = setMap

	} else {

		auth, _ := b.GetAuthUser()
		control, _ := b.GetControllerAndAction()

		//这里需要可配
		if b.Ctx.Request.Method != "GET" && control != "LoginController" && auth.UserID != 1 {

			b.RES(500, nil, "演示账号不能提交数据")

		}
	}

}

func (b *AdminController) OK(data interface{}) {
	b.RES(200, data, "")
	return
}

func (b *AdminController) ERROR(msg string) {
	b.RES(500, nil, msg)
	return
}

func (b *AdminController) GetUserID() (uid uint64) {

	auth, _ := b.GetAuthUser()
	if auth != nil {
		uid = auth.UserID
	}
	return

}

func (b *AdminController) RES(code int, data interface{}, msg string) {
	res := ApiRes{
		Code: code,
		Data: data,
		Msg:  msg,
	}

	if b.Ctx.Request.Method != "GET" {
		result, _ := json.Marshal(res)
		by := b.Ctx.Input.RequestBody

		_ = models.NewLog().Logger(b.GetUserID(), models.LoggerReq{
			ReqMethod: b.Ctx.Request.Method,
			ReqUrl:    b.Ctx.Request.URL.RequestURI(),
			ReqBody:   string(by),
			//
			ReqIp:  b.Ctx.Request.Header.Get("Remote_addr"), //b.Ctx.Input.IP(),
			Result: string(result),
		})
	}

	_ = b.Resp(res)
	return
}

func (b *AdminController) View() {

	b.view("", nil)

	return
}

func (b *AdminController) ViewTpl(tpl string) {

	b.view(tpl, nil)

	return
}
func (b *AdminController) ViewTplData(tpl string, data map[string]interface{}) {

	b.view(tpl, data)

	return
}
func (b *AdminController) ViewData(data map[string]interface{}) {

	b.view("", data)

	return
}
func (b *AdminController) view(tpName string, data map[string]interface{}) {
	ctrl, act := b.Controller.GetControllerAndAction()
	ctrl = strings.ToLower(ctrl[0:strings.Index(ctrl, "Controller")])
	if len(tpName) <= 0 {
		b.TplName = fmt.Sprintf("%s/%s.html", strings.ToLower(ctrl), strings.ToLower(act))
	} else {
		b.TplName = fmt.Sprintf("%s/%s.html", strings.ToLower(ctrl), tpName)
	}

	if data != nil {
		for k, v := range data {
			b.Data[k] = v
		}
	}

	return
}
func (b *AdminController) IndexRouter() string {
	return IndexRouter + "?ts=" + strconv.FormatInt(time.Now().UnixNano(), 10)
}

func (b *AdminController) Authorization() bool {

	auth, err := b.GetAuthUser()
	noAuth := b.getNoAuth()

	if noAuth != nil {
		if auth != nil && strings.ToLower(b.Ctx.Request.URL.Path) == LoginRouter {
			b.Redirect(b.IndexRouter(), 301)
			return true
		}
		return true
	}

	if auth == nil || err != nil {

		if strings.ToLower(b.Ctx.Request.URL.Path) == LoginRouter {
			return true
		}

		//未授权
		if b.Ctx.Input.IsAjax() {

			b.RES(http.StatusUnauthorized, nil, "未登录")
			//ajax
			return false
		}
		//跳到登录页
		b.Ctx.Redirect(http.StatusMovedPermanently, LoginRouter+"?"+RedirectUrlKey+"="+b.buildRedirectUrl())
		return false

	}

	if strings.ToLower(b.Ctx.Request.URL.Path) == LoginRouter {
		b.Redirect(b.IndexRouter(), 301)
		return true
	}

	return true

}

//RedirectUrl 获取redirect_url
func (b *AdminController) RedirectUrl() string {
	return b.Ctx.Request.URL.Query().Get("redirect_url")
}

//buildRedirectUrl 构建redirect_url
func (b *AdminController) buildRedirectUrl() string {

	allQ := b.Ctx.Request.URL.Query()
	rUrl := b.Ctx.Request.URL.Path
	i := 0
	for k, q := range allQ {
		i++
		if k == "ts" {
			//时间戳更新一下
			q = []string{strconv.FormatInt(time.Now().UnixNano(), 10)}
		}
		if i == 1 {
			rUrl += "?" + k + "=" + q[0]
		} else {
			rUrl += "&" + k + "=" + q[0]
		}

	}
	return url.QueryEscape(rUrl)

}
